home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / VGX / morph / morph.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  44KB  |  1,548 lines

  1. /*
  2.  * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18.     morph.c - Use VGX texture mapping to do image metamorphosis.
  19.  
  20.     Tim Heidmann, Silicon Graphics
  21.     Created          May  1, 1991
  22.     Last Edit   November 25, 1991
  23. */
  24.  
  25. /*
  26.     Morph'ing is a technique and term first used in production by Industrial
  27.     Light and Magic for the film "Willow".  Real-time morph'ing using texture
  28.     maps is from an idea by Michael Wahrman.  Originally written for the
  29.     George Coates Performance Works theatrical project "Invisible Site".
  30. */
  31.  
  32. #include <stdio.h>
  33. #include <math.h>
  34. #include <gl.h>
  35. #include <device.h>
  36. #include <gl/image.h>
  37.  
  38. /* Window, mouse, and events */
  39. long xOrig, yOrig;
  40. long winWidth = 512, winHeight = 512;
  41. float winWidthFactor, winHeightFactor;
  42. long performXOrig, performYOrig, performXSize = -1, performYSize;
  43. float performAspect;
  44. #define MINDRAGDIST  0.01
  45. #define MAXHITDIST   0.02
  46. #define RGB_GRAY     0x00505050
  47. #define RGB_RED      0x000000a0
  48. #define RGB_GREEN    0x0000a000
  49. #define RGB_BLUE     0x00a00000
  50. #define RGB_YELLOW   0x0000a0a0
  51. #define RGB_CYAN     0x00a0a000
  52. #define RGB_MAGENTA  0x00a000a0
  53. #define RGB_WHITE    0x00ffffff
  54. #define RGB_BLACK    0x00000000
  55. #define RGB_BRIGHTER 0x00505050
  56. long colorList[] =
  57.     {RGB_RED, RGB_GREEN, RGB_BLUE, RGB_YELLOW, RGB_CYAN, RGB_MAGENTA};
  58. long triColorList[] =
  59.     {RGB_RED, RGB_GREEN, RGB_BLUE, RGB_YELLOW, RGB_CYAN, RGB_MAGENTA};
  60.  
  61. float tev_val[] = {TV_NULL};
  62. float tex_val[] =
  63.      {TX_MINFILTER, TX_BILINEAR, TX_MAGFILTER, TX_BILINEAR, TX_NULL};
  64. #define MINPADKEY    PAD1
  65. #define MAXPADKEY    PAD9
  66. /* Button numbers for numeric pad keys:
  67.                     0   1   2   3   4   5   6   7   8   9   */
  68. int buttonNum[] = {59, 58, 64, 65, 63, 69, 70, 67, 68, 75};
  69.  
  70.  
  71. /* Program state */
  72. enum {selmoveVertices, addVertices, connectVertices}
  73.     clickMode = selmoveVertices;
  74. int performFlag = TRUE;
  75. int fullScreen = FALSE;
  76. int shiftDown = 0;
  77. long mainMenu, vColorMenu, cColorMenu, targetGotoMenu, targetDeleteMenu;
  78. long performMenu;
  79. int dbxVertex = -1, nDbxEdges = 0, dbxEdges[10];
  80. long *bgImage = NULL;
  81. int bgXsize = -1, bgYsize = -1;
  82. int flushQueue = FALSE;
  83. int autoRun = FALSE;
  84. int showMesh = FALSE;
  85. int showTwins = FALSE;
  86.  
  87.  
  88. /* Working Mesh data structures */
  89. float crossArm = 0.008;
  90. #define MAXVERTICES 100
  91. struct vertlist_tag {
  92.     float x, y;
  93.     long color;
  94.     int selected;
  95. } vertexList[MAXVERTICES];
  96. int nVertices = 0;
  97. long vColor = RGB_YELLOW;
  98.  
  99. #define MAXCNX 600
  100. struct cnxlist_tag {
  101.     int v0, v1;
  102.     long color;
  103.     int selected;
  104. } cnxList[MAXCNX];
  105. long nCnx = 0;
  106. long cColor = RGB_BLUE;
  107.  
  108. #define MAXTRIANGLES 400
  109. struct tri_tag {
  110.     int v0, v1, v2;
  111. } triangleList[MAXTRIANGLES];
  112. int nTriangles = 0;
  113.  
  114.  
  115. /* Collection of target images and meshes */
  116. #define MAXTARGETS 12
  117. struct target_tag {
  118.     long *image;
  119.     struct vertlist_tag *vertexList;
  120.     struct cnxlist_tag *cnxList;
  121.     struct tri_tag *triangleList;
  122.     int xSize, ySize, nVertices, nCnx, nTriangles, textureIndex;
  123. } target[MAXTARGETS];
  124. int nTargets = 0;
  125. int thisTarget = -1, destTarget = -1;
  126. long thisTargetColor, destTargetColor;
  127. struct vertlist_tag tmpVertexList[MAXVERTICES];
  128. int nTmpVertices = 0;
  129.  
  130. int currentSpeed = 5;
  131. /* Number of frames per transition for each numeric pad key:
  132.                     0  1   2   3   4   5   6   7   8    9   */
  133. int frameCount[] = {1, 5, 10, 15, 20, 30, 45, 60, 90, 120};
  134.  
  135. /* Temp structure for doing triangulation */
  136. #define MAXEDGESPERVERTEX 17
  137. struct {
  138.     int nEdges;
  139.     struct {
  140.         int index;     /* Index into edge (cnx) list */
  141.         int marked;    /* marked[i] TRUE => edge[i]-[i+1] angle tried. */
  142.     } edge[MAXEDGESPERVERTEX];
  143. } vertexEdges[MAXVERTICES];
  144.  
  145. /* Selected data structure */
  146. int selectedVList[MAXVERTICES];
  147. int nVSelected = 0;
  148. int selectedCList[MAXCNX];
  149. int nCSelected = 0;
  150.  
  151. /* Prototypes */
  152. void
  153. ParseArgs(int c, char *v[]);
  154. void
  155. BadCommand(char *name);
  156. void
  157. DoClick(short mx, short my);
  158.  
  159. int
  160. AddVertex(float x, float y);
  161. void
  162. DeleteVertex(int iVertex);
  163. int
  164. HitVertex(float x, float y);
  165.  
  166. void
  167. AddSelectVertex(int iVertex);
  168. void
  169. SelectVertex(int iVertex);
  170. void
  171. DeleteVSelection(int iSelect);
  172. void
  173. MoveSelected(float dx, float dy);
  174. void
  175. DeleteSelectedVertices();
  176.  
  177. int
  178. AddCnx(int v0, int v1);
  179. void
  180. DeleteCnx(int iCnx);
  181. int
  182. HitCnx(float x, float y);
  183.  
  184. void
  185. AddSelectCnx(int iCnx);
  186. void
  187. SelectCnx(int iCnx);
  188. void
  189. DeleteCSelection(int iSelect);
  190. void
  191. DeleteSelectedCnx();
  192.  
  193. int
  194. AddTriangle(int v0, int v1, int v2);
  195.  
  196. int
  197. ReadLine(FILE *myf, char *buf);
  198. int
  199. ReadCnx(char *filename);
  200. int
  201. WriteCnx(char *filename);
  202.  
  203. void
  204. CnxToTri();
  205.  
  206.  
  207. /*******************************************************************************
  208.  
  209.     Main
  210.  
  211. *******************************************************************************/
  212.  
  213. main(int argc, char *argv[]) {
  214.     short dev, val;
  215.     short initMouseX, initMouseY;
  216.     int iNumPadKey, iTarget;
  217.     int redrawFlag, doneFlag;
  218.  
  219.     printf("\n     Loading data -- please wait ...\n");
  220.  
  221.     ParseArgs(argc, argv);
  222.  
  223.     printf("     Finished loading data!\n\n");
  224.  
  225.     InitGfx();
  226.  
  227.     for (doneFlag=FALSE; !doneFlag;) {
  228.         if (performFlag) {
  229.             /* Performance mode */
  230.             if (flushQueue) {
  231.                 while (qtest()) qread(&val);
  232.                 flushQueue = FALSE;
  233.         autoRun = FALSE;
  234.                 setbell(1); ringbell();
  235.             }
  236.  
  237.             if (qtest()) switch (dev = qread(&val)) {
  238.             case ESCKEY:
  239.                 doneFlag = TRUE;
  240.                 break;
  241.         case RIGHTMOUSE:
  242.         autoRun = FALSE;
  243.         switch (dopup(performMenu)) {
  244.         case 1: /* To Edit Mode */
  245.             performFlag = FALSE;
  246.             SetEditGfx();
  247.             DrawWindow();
  248.             break;
  249.         case 2: /* Auto Run */
  250.             autoRun = TRUE;
  251.             break;
  252.         case 3: /* Toggle Show Mesh */
  253.             showMesh = !showMesh;
  254.             DrawPerformWindow();
  255.             break;
  256.         case 4: /* Toggle Twin Images */
  257.             showTwins = !showTwins;
  258.             performAspect = (showTwins ? 2.0 : 1.0) *
  259.             ((float)performYSize)/performXSize;
  260.             DrawPerformWindow();
  261.             break;
  262.         case 99: /* Exit */
  263.             doneFlag = TRUE;
  264.             break;
  265.         }
  266.         break;
  267.             case REDRAW:
  268.                 reshapeviewport();
  269.         getorigin(&performXOrig, &performYOrig);
  270.         getsize(&performXSize, &performYSize);
  271.         performAspect = (showTwins ? 2.0 : 1.0) *
  272.                     ((float)performYSize)/performXSize;
  273.                 DrawPerformWindow();
  274.                 break;
  275.             default:
  276.                 if (dev>=F1KEY && dev<=F12KEY) {
  277.                     /* Decode FKEY, or -1 for none. Initiate transition. */
  278.                     if (val) {
  279.             autoRun = FALSE;
  280.  
  281.             thisTarget = destTarget;
  282.                         iTarget = dev - F1KEY;
  283.                         destTarget = iTarget<nTargets ? iTarget : -1;
  284.                         AnimateTransition();
  285.  
  286.                     }
  287.                 }
  288.                 else if (dev>=MINPADKEY && dev<=MAXPADKEY) {
  289.                     /* Decode numeric pad button, set current speed */
  290.                     if (val) {
  291.             autoRun = FALSE;
  292.                         for (iNumPadKey=0; iNumPadKey<=9; iNumPadKey++)
  293.                             if (buttonNum[iNumPadKey] == dev)
  294.                                 {currentSpeed = iNumPadKey; break;}
  295.             }
  296.                 }
  297.                 break;
  298.             }
  299.  
  300.         if (autoRun && !qtest()) {
  301.         thisTarget = destTarget;
  302.         destTarget = (random() & 255) / 256.0 * nTargets;
  303.         currentSpeed = random() % 7 + 3; /* Select speed 3-9 */
  304.         AnimateTransition();
  305.         }
  306.  
  307.             if (redrawFlag && !qtest()) {
  308.                 DrawPerformWindow();
  309.                 redrawFlag = FALSE;
  310.             }
  311.         }
  312.         else
  313.             /* Mesh editing mode */
  314.             switch (dev = qread(&val)) {
  315.             case LEFTMOUSE:
  316.                 qread(&initMouseX); qread(&initMouseY);
  317.                 if (val) DoClick(initMouseX, initMouseY);
  318.                 break;
  319.             case RIGHTMOUSE:
  320.                 if (val) doneFlag = DoMenu();
  321.                 break;
  322.             case LEFTSHIFTKEY:
  323.             case RIGHTSHIFTKEY:
  324.                 shiftDown = val;
  325.                 break;
  326.             case BACKSPACEKEY:
  327.                 /* Don't delete vertices in connect mode.
  328.                    Reset selection too. */
  329.                 if (clickMode == connectVertices) SelectVertex(-1);
  330.                 DeleteSelectedVertices();
  331.                 DeleteSelectedCnx();
  332.                 DrawWindow();
  333.                 break;
  334.             case REDRAW:
  335.                 reshapeviewport();
  336.                 getorigin(&xOrig, &yOrig);
  337.                 DrawWindow();
  338.                 break;
  339.         case ESCKEY:
  340.         doneFlag = TRUE;
  341.         break;
  342.             default:
  343.                 break;
  344.             }
  345.     }
  346. }
  347.  
  348. void
  349. ParseArgs(int c, char *v[]) {
  350.     int i;
  351.     FILE *f;
  352.     char *cmdName, imgFile[100], cnxFile[100], buf[100];
  353.     int fileRead;
  354.  
  355.     cmdName = v[0];
  356.     fileRead = FALSE;
  357.     for (c--, v++; c>0; c--, v++) {
  358.         if (v[0][0] != '-') {
  359.             if (fileRead) BadCommand(cmdName);
  360.             if ((f = fopen(v[0], "r")) == NULL)
  361.                 fprintf(stderr, "Cannot open master file %s\n", v[0]);
  362.             else {
  363.                 for (i=0; i<MAXTARGETS; i++) {
  364.                     if (!ReadLine(f, buf)) break;
  365.                     sscanf(buf, "%s %s", imgFile, cnxFile);
  366.  
  367.             if (!ReadImg(imgFile)) continue;
  368.             if (ReadCnx(cnxFile) < 0) continue;
  369.             AddTarget();
  370.                 }
  371.                 fclose(f);
  372.                 fileRead = TRUE;
  373.             }
  374.         } else /* v[0][0] == '-' */
  375.             switch (v[0][1]) {
  376.         case 'p': performFlag = TRUE; break;
  377.         case 'f': fullScreen = TRUE; performFlag = TRUE; break;
  378.         case 'e': performFlag = FALSE; break;
  379.         default: BadCommand(cmdName);
  380.         }
  381.     }
  382. }
  383.  
  384. void
  385. BadCommand(char *name) {
  386.     fprintf(stderr, "usage: %s [-p] [-f] [-e] [<master file>]\n", name);
  387.     exit(1);
  388. }
  389.  
  390. InitGfx() {
  391.     int i;
  392.  
  393.     /* Open the window */
  394. #ifdef DEBUG
  395.     foreground();
  396. #endif
  397.     if (performFlag) {
  398.     if (fullScreen)
  399.         prefposition(0, getgdesc(GD_XPMAX)-1, 0, getgdesc(GD_YPMAX)-1);
  400.         winopen("Morph");
  401.     getorigin(&performXOrig, &performYOrig);
  402.     getsize(&performXSize, &performYSize);
  403.     performAspect =
  404.         (showTwins ? 2.0 : 1.0) * ((float)performYSize)/performXSize;
  405.     /* Allow resizing the perform window */
  406.     winconstraints();
  407.     /* Position the edit window in the middle of the screen */
  408.         xOrig = (getgdesc(GD_XPMAX) - 1 - winWidth) / 2;
  409.         yOrig = (getgdesc(GD_YPMAX) - 1 - winHeight) / 2;
  410.         thisTarget = destTarget = -1;
  411.         tevdef(1, 0, tev_val);
  412.         SetPerformGfx();
  413.     } else {
  414.         prefsize(winWidth, winHeight);
  415.         winopen("Morph");
  416.         getorigin(&xOrig, &yOrig);
  417.         tevdef(1, 0, tev_val);
  418.         SetEditGfx();
  419.     }
  420.     winWidthFactor = 1.0 / winWidth;
  421.     winHeightFactor = 1.0 / winHeight;
  422.  
  423.     /*  Check if texture mapping supported. */
  424.     if( !getgdesc( GD_TEXTURE ) ) {
  425.     printf("\n\nWARNING -- This machine does not support texture mapping,\n");
  426.     printf("           which is required to perform the morphing.\n");
  427.     }
  428.  
  429.     RGBmode();
  430.     doublebuffer();
  431.     gconfig();
  432.  
  433.     ortho2(0.0, 1.0, 0.0, 1.0);
  434.     cpack(RGB_BLACK);
  435.     clear();
  436.     swapbuffers();
  437.  
  438.     /* Queue the devices */
  439.     qdevice(LEFTMOUSE);
  440.     tie(LEFTMOUSE, MOUSEX, MOUSEY);
  441.     qdevice(RIGHTMOUSE);
  442.     qdevice(LEFTSHIFTKEY);
  443.     qdevice(RIGHTSHIFTKEY);
  444.     qdevice(BACKSPACEKEY);
  445.     for (i=F1KEY; i<=F12KEY; i++) qdevice(i);
  446.     qdevice(ESCKEY);
  447.     for (i=0; i<=9; i++) qdevice(buttonNum[i]);
  448.  
  449.     /* Set up the menus */
  450.     mainMenu = defpup("");
  451.     vColorMenu = defpup("Vertex Color %t");
  452.     addtopup(vColorMenu,
  453.         "Red%x31|Green%x32|Blue%x33|Yellow%x34|Cyan%x35|Magenta%x36");
  454.     cColorMenu = defpup("Connection Color %t");
  455.     addtopup(cColorMenu,
  456.         "Red%x21|Green%x22|Blue%x23|Yellow%x24|Cyan%x25|Magenta%x26");
  457.     targetGotoMenu = defpup("No Targets %t");
  458.     targetDeleteMenu = defpup("No Targets %t");
  459.     performMenu = defpup("Morph %t");
  460.     addtopup(performMenu, "Edit Mode%x1%l|Auto Run%x2");
  461.     addtopup(performMenu, "Toggle Mesh%x3|Toggle Twin Images%x4%l|Exit %x99");
  462.  
  463.     MakeTargetMenus();
  464.     MakeMenu();
  465. }
  466.  
  467. SetEditGfx() {
  468.     int i;
  469.  
  470.     /* Set up graphics for mesh editing.
  471.        Window to original size, border.  Ortho projection. */
  472. /*
  473.     winposition(xOrig, xOrig+winWidth-1, yOrig, yOrig+winHeight-1);
  474. */
  475.     prefsize(winWidth, winHeight);
  476.     winconstraints();
  477.     reshapeviewport();
  478.     ortho2(0.0, 1.0, 0.0, 1.0);
  479.  
  480.     /* No texture mapping, no alphablending */
  481.     tevbind(TV_ENV0, 0);
  482.     blendfunction(BF_ONE, BF_ZERO);
  483. }
  484.  
  485. SetPerformGfx() {
  486.     int i;
  487.  
  488.     /* Set up graphics for performance. */
  489.     if (performXSize > 0)
  490.     winposition(performXOrig, performXOrig+performXSize-1,
  491.                 performYOrig, performYOrig+performYSize-1);
  492.     winconstraints();
  493.     reshapeviewport();
  494.  
  495.     /* Turn texture mapping on, alphablending on */
  496.     for (i=0; i<nTargets; i++)
  497.         texdef2d(target[i].textureIndex, 4,
  498.             target[i].xSize, target[i].ySize, target[i].image, 0, tex_val);
  499.     tevbind(TV_ENV0, 1);
  500.     blendfunction(BF_SA, BF_ONE);
  501. }
  502.  
  503. void
  504. DoClick(short mx, short my) {
  505.     int iVertex, iCnx;
  506.     float xFirst, yFirst, xNew, yNew, xLast, yLast, dist;
  507.     enum {starting, tracking, done} trackState;
  508.  
  509.     xFirst = (mx - xOrig) * winWidthFactor;
  510.     yFirst = (my - yOrig) * winHeightFactor;
  511.  
  512.     switch (clickMode) {
  513.     case selmoveVertices:
  514.         /* Act on the hit to select new vertices */
  515.         if ((iVertex = HitVertex(xFirst, yFirst)) >= 0)
  516.             /* Vertex hit. Toggle selection or select just this */
  517.             if (shiftDown) AddSelectVertex(iVertex);
  518.             else {
  519.                 SelectVertex(iVertex);
  520.                 SelectCnx(-1);
  521.             }
  522.         else if ((iCnx = HitCnx(xFirst, yFirst)) >= 0)
  523.             /* Connection hit. Toggle selection or select just this */
  524.             if (shiftDown) AddSelectCnx(iCnx);
  525.             else {
  526.                 SelectCnx(iCnx);
  527.                 SelectVertex(-1);
  528.             }
  529.         else {
  530.             /* Nothing hit. Unless shiftkey is down, select nothing */
  531.             if (!shiftDown) SelectVertex(-1); SelectCnx(-1);
  532.         }
  533.         DrawWindow();
  534.  
  535.         /* Now track any movement. Don't start moving until the mouse has been
  536.            dragged a certain minimum amount. */
  537.         xLast = xFirst; yLast = yFirst;
  538.         for (trackState = starting;
  539.         getbutton(LEFTMOUSE) && trackState != done; ) {
  540.             xNew = (getvaluator(MOUSEX) - xOrig) * winWidthFactor;
  541.             yNew = (getvaluator(MOUSEY) - yOrig) * winHeightFactor;
  542.  
  543.             switch (trackState) {
  544.             case starting:
  545.                 dist = fabs(xFirst - xNew) + fabs(yFirst - yNew);
  546.                 if (dist > MINDRAGDIST) trackState = tracking;
  547.                 break;
  548.             case tracking:
  549.                 MoveSelected(xNew - xLast, yNew - yLast);
  550.                 DrawWindow();
  551.                 xLast = xNew; yLast = yNew;
  552.                 break;
  553.             }
  554.         }
  555.         break;
  556.  
  557.     case addVertices:
  558.         AddVertex(xFirst, yFirst);
  559.         DrawWindow();
  560.         break;
  561.     case connectVertices:
  562.         /* If vertex already selected, connect new selection to old,
  563.        update selection */
  564.         iVertex = HitVertex(xFirst, yFirst);
  565.         if (iVertex >= 0) {
  566.             if (nVSelected)
  567.                 SelectCnx(AddCnx(selectedVList[0], iVertex));
  568.         }
  569.         SelectVertex(iVertex);
  570.         DrawWindow();
  571.         break;
  572.     default:
  573.         fprintf(stderr, "WHOA! Unknown mode!\n");
  574.         break;
  575.     }
  576. }
  577.  
  578. int
  579. AddVertex(float x, float y) {
  580.     vertexList[nVertices].x = x;
  581.     vertexList[nVertices].y = y;
  582.     vertexList[nVertices].color = vColor;
  583.     vertexList[nVertices].selected = FALSE;
  584.     nVertices++;
  585.  
  586.     return nVertices-1;
  587. }
  588.  
  589. void
  590. DeleteVertex(int iVertex) {
  591.     int i;
  592.  
  593.     /* Shift higher vertex records down */
  594.     for (i=iVertex; i<nVertices-1; i++)
  595.         vertexList[i] = vertexList[i+1];
  596.     nVertices--;
  597.  
  598.     /* Renumber connections referencing higher vertices,
  599.        Delete connections referencing this vertex */
  600.     for (i=0; i<nCnx; ) {
  601.         if (cnxList[i].v0 == iVertex || cnxList[i].v1 == iVertex) DeleteCnx(i);
  602.         else {
  603.             if (cnxList[i].v0 > iVertex) cnxList[i].v0--;
  604.             if (cnxList[i].v1 > iVertex) cnxList[i].v1--;
  605.             i++;    /* We are keeping this connection, bump to next one */
  606.         }
  607.     }
  608.  
  609.     /* Delete or renumber selections referencing this vertex */
  610.     for (i=0; i<nVSelected; )
  611.         if (selectedVList[i] == iVertex) DeleteVSelection(i);
  612.         else {
  613.             if (selectedVList[i] > iVertex) selectedVList[i]--;
  614.             i++;
  615.         }
  616. }
  617.  
  618. int
  619. HitVertex(float x, float y) {
  620.     /* Return index of 1st vertex near given point, or -1 if none */
  621.     int i;
  622.  
  623.     for (i=0; i<nVertices; i++) {
  624.         if (fabs(x - vertexList[i].x) + fabs(y - vertexList[i].y) < MAXHITDIST)
  625.             return i;
  626.     }
  627.     
  628.     return -1;
  629. }
  630.  
  631. void
  632. AddSelectVertex(int iVertex) {
  633.     /* Toggle membership of iVertex in list of currently selected vertices */
  634.     int i, j, found;
  635.  
  636.     /* Check selected list for iVertex.  If there, remove it. */
  637.     found = FALSE;
  638.     for (i=0; i<nVSelected; i++)
  639.         if (selectedVList[i] == iVertex) {
  640.             DeleteVSelection(i);
  641.             vertexList[iVertex].selected = FALSE;
  642.             found = TRUE;
  643.             break;
  644.         }
  645.  
  646.     /* Otherwise, add it */
  647.     if (!found) {
  648.         selectedVList[nVSelected] = iVertex;
  649.         nVSelected++;
  650.         vertexList[iVertex].selected = TRUE;
  651.     }
  652. }
  653.  
  654. void
  655. SelectVertex(int iVertex) {
  656.     /* Reset the selected vertex list to only this one (-1 => none) */
  657.     int i;
  658.  
  659.     /* If already selected, do nothing */
  660.     if (vertexList[iVertex].selected) return;
  661.  
  662.     /* Turn off selected flag in all entities but this one */
  663.     for (i=0; i<nVSelected; i++)
  664.         vertexList[selectedVList[i]].selected = FALSE;
  665.  
  666.     /* Reset the selected list */
  667.     if (iVertex >= 0) {
  668.         selectedVList[0] = iVertex;
  669.         vertexList[iVertex].selected = TRUE;
  670.         nVSelected = 1;
  671.     } else {
  672.         nVSelected = 0;
  673.     }
  674. }
  675.  
  676. void
  677. DeleteVSelection(int iSelect) {
  678.     int i;
  679.  
  680.     for (i=iSelect; i<nVSelected-1; i++) selectedVList[i] = selectedVList[i+1];
  681.     nVSelected--;
  682. }
  683.  
  684. void
  685. MoveSelected(float dx, float dy) {
  686.     /* Move all selected vertices by given increments */
  687.     int i;
  688.  
  689.     for (i = 0; i < nVSelected; i++) {
  690.         vertexList[selectedVList[i]].x += dx;
  691.         vertexList[selectedVList[i]].y += dy;
  692.     }
  693. }
  694.  
  695. void
  696. DeleteSelectedVertices() {
  697.     /* Delete all selected vertices */
  698.     int i;
  699.  
  700.     /* Make changes to the vertex list */
  701.     for (i=0; i<nVertices; )
  702.         if (vertexList[i].selected) DeleteVertex(i);
  703.         else i++;
  704. }
  705.  
  706. int
  707. AddCnx(int v0, int v1) {
  708.     int i;
  709.  
  710.     /* Check for degenerate edges */
  711.     if (v0 == v1) return -1;
  712.  
  713.     /* Check for this edge already existing */
  714.     for (i=0; i<nCnx; i++) {
  715.         if (cnxList[i].v0 == v0)
  716.             if (cnxList[i].v1 == v1) return i;
  717.             else ;
  718.         if (cnxList[i].v0 == v1)
  719.             if (cnxList[i].v1 == v0) return i;
  720.             else ;
  721.     }
  722.  
  723.     /* Okay, add it */
  724.     cnxList[nCnx].v0 = v0;
  725.     cnxList[nCnx].v1 = v1;
  726.     cnxList[nCnx].color = cColor;
  727.     cnxList[nCnx].selected = FALSE;
  728.     nCnx++;
  729.  
  730.     return nCnx-1;
  731. }
  732.  
  733. void
  734. DeleteCnx(int iCnx) {
  735.     /* Delete the given connection */
  736.     int i;
  737.  
  738.     /* Shift higher records down */
  739.     for (i=iCnx; i<nCnx-1; i++)
  740.         cnxList[i] = cnxList[i+1];
  741.     nCnx--;
  742.  
  743.     /* Delete or renumber selection info */
  744.     for (i=0; i<nCSelected; )
  745.         if (selectedCList[i] == iCnx) DeleteCSelection(i);
  746.         else {
  747.             if (selectedCList[i] > iCnx) selectedCList[i]--;
  748.             i++;
  749.         }
  750. }
  751.  
  752. int
  753. HitCnx(float x, float y) {
  754.     /* Return index of 1st connection near given point, or -1 if none */
  755.     int i, v0, v1;
  756.     float dx, dy, len, a, b, c, a2, b2, c2, dist;
  757.  
  758.     for (i=0; i<nCnx; i++) {
  759.         v0 = cnxList[i].v0;
  760.         v1 = cnxList[i].v1;
  761.         dx = vertexList[v1].x - vertexList[v0].x;
  762.         dy = vertexList[v1].y - vertexList[v0].y;
  763.         len = fsqrt(dx*dx + dy*dy);
  764.         a = dy / len; b = -dx / len;
  765.         c = -(a*vertexList[v0].x + b*vertexList[v0].y);
  766.         dist = a*x + b*y + c;
  767.         if (fabs(dist) > MAXHITDIST) continue;
  768.         a2 = -b/len; b2 = a/len;
  769.         c2 = -(a2*vertexList[v0].x + b2*vertexList[v0].y);
  770.         dist = a2*x + b2*y + c2;
  771.         if (dist < 0.0 || dist > 1.0) continue;
  772.  
  773.         return i;
  774.     }
  775.     
  776.     return -1;
  777. }
  778.  
  779. void
  780. AddSelectCnx(int iCnx) {
  781.     /* Toggle membership of iCnx in list of currently selected connections */
  782.     int i, j, found;
  783.  
  784.     /* Check selected list for iCnx.  If there, remove it. */
  785.     found = FALSE;
  786.     for (i=0; i<nCSelected; i++)
  787.         if (selectedCList[i] == iCnx) {
  788.             DeleteCSelection(i);
  789.             cnxList[iCnx].selected = FALSE;
  790.             found = TRUE;
  791.             break;
  792.         }
  793.  
  794.     /* Otherwise, add it */
  795.     if (!found) {
  796.         selectedCList[nCSelected] = iCnx;
  797.         nCSelected++;
  798.         cnxList[iCnx].selected = TRUE;
  799.     }
  800. }
  801.  
  802. void
  803. SelectCnx(int iCnx) {
  804.     /* Reset the selected connection list to only this one (-1 => none) */
  805.     int i;
  806.  
  807.     /* If already selected, do nothing */
  808.     if (cnxList[iCnx].selected) return;
  809.  
  810.     /* Turn off selected flag in all connections but this one */
  811.     for (i=0; i<nCSelected; i++)
  812.         cnxList[selectedCList[i]].selected = FALSE;
  813.  
  814.     /* Reset the selected list */
  815.     if (iCnx >= 0) {
  816.         selectedCList[0] = iCnx;
  817.         cnxList[iCnx].selected = TRUE;
  818.         nCSelected = 1;
  819.     } else {
  820.         nCSelected = 0;
  821.     }
  822. }
  823.  
  824. void
  825. DeleteCSelection(int iSelect) {
  826.     int i;
  827.  
  828.     for (i=iSelect; i<nCSelected-1; i++) selectedCList[i] = selectedCList[i+1];
  829.     nCSelected--;
  830. }
  831.  
  832. void
  833. DeleteSelectedCnx() {
  834.     /* Delete all selected connections */
  835.     int i;
  836.     for (i=0; i<nCnx; )
  837.         if (cnxList[i].selected) DeleteCnx(i);
  838.         else i++;
  839. }
  840.  
  841. PrintVSelected() {
  842.     int i;
  843.     
  844.     fprintf(stdout, "%d Vertices Selected:", nVSelected);
  845.     for (i=0; i<nVSelected; i++)
  846.         fprintf(stdout, " %d", selectedVList[i]);
  847.     fprintf(stdout, "\n");
  848. }
  849.  
  850. int
  851. AddTriangle(int v0, int v1, int v2) {
  852.     triangleList[nTriangles].v0 = v0;
  853.     triangleList[nTriangles].v1 = v1;
  854.     triangleList[nTriangles].v2 = v2;
  855.     return nTriangles++;
  856. }
  857.  
  858.  
  859. /****************************************************************************
  860.  
  861.  File I/O
  862.  
  863. ****************************************************************************/
  864. int
  865. ReadLine(FILE *myf, char *buf) {
  866.     do {
  867.         if (fgets(buf, 120, myf) == NULL) return FALSE;
  868.     } while (buf[0] == '#');
  869.     return TRUE;
  870. }
  871.  
  872. int
  873. ReadCnx(char *filename) {
  874.     int i;
  875.     char line[120];
  876.     FILE *f;
  877.  
  878.     /* Open the file and check the type */
  879.     if ((f = fopen(filename, "r")) == NULL) {
  880.         fprintf(stderr, "Cannot open file %s\n", filename);
  881.         return -1;
  882.     }
  883.     fscanf(f, "%s\n", line);
  884.     if (strcmp(line, "2DCnx") != 0) {
  885.         fprintf(stderr, "File %s is not a connection file.\n", filename);
  886.         return -1;
  887.     }
  888.  
  889.     /* Reset the internal structures */
  890.     nVertices = nCnx = 0;
  891.     nVSelected = nCSelected = 0;
  892.  
  893.     /* Read the vertices, then the connections */
  894.     if (!ReadLine(f, line)) goto oops;
  895.     sscanf(line, "%d", &nVertices);
  896.     for (i=0; i < nVertices; i++) {
  897.         if (!ReadLine(f, line)) goto oops;
  898.         if (sscanf(line, "%f %f %x",
  899.                 &vertexList[i].x, &vertexList[i].y, &vertexList[i].color) != 3)
  900.             goto oops;
  901.     }
  902.  
  903.     if (!ReadLine(f, line)) goto oops;
  904.     sscanf(line, "%d", &nCnx);
  905.     for (i=0; i < nCnx; i++) {
  906.         if (!ReadLine(f, line)) goto oops;
  907.         if (sscanf(line, "%d %d %x",
  908.                 &cnxList[i].v0, &cnxList[i].v1, &cnxList[i].color) != 3)
  909.             goto oops;
  910.     }
  911.     fclose(f);
  912.     return 0;
  913.  
  914. oops:
  915.     fclose(f);
  916.     fprintf(stderr, "Error reading file %s.\n  Input: %s\n", filename, line);
  917.     nVertices = nCnx = 0;
  918.     return -1;
  919. }
  920.  
  921. int
  922. WriteCnx(char *filename) {
  923.     int i;
  924.     FILE *f;
  925.  
  926.     if ((f = fopen(filename, "w")) == NULL) {
  927.         fprintf(stderr, "Cannot open output file %s\n", filename);
  928.         return FALSE;
  929.     }
  930.     fprintf(f, "2DCnx\n");
  931.     fprintf(f, "%d\n", nVertices);
  932.     for (i=0; i<nVertices; i++)
  933.         fprintf(f, "%f %f %x\n",
  934.                 vertexList[i].x, vertexList[i].y, vertexList[i].color);
  935.     fprintf(f, "%d\n", nCnx);
  936.     for (i=0; i<nCnx; i++)
  937.         fprintf(f, "%d %d %x\n",
  938.             cnxList[i].v0, cnxList[i].v1, cnxList[i].color);
  939.     fclose(f);
  940. }
  941.  
  942.  
  943. int
  944. ReadImg(char *filename) {
  945.     register IMAGE *image;
  946.     register int x, y, xsize, ysize;
  947.     register int z, zsize;
  948.     short buf[4096]; 
  949.  
  950.     if ((image=iopen(filename, "r")) == NULL ) {
  951.         fprintf(stderr,"readimg: can't open input file %s\n",filename);
  952.         return FALSE;
  953.     }
  954.     xsize = image->xsize;
  955.     ysize = image->ysize;
  956.     zsize = image->zsize;
  957.     if(zsize<3) {
  958.         fprintf(stderr,"readimg: this is not an RGB image file\n");
  959.         return FALSE;
  960.     }
  961.  
  962.     if (bgXsize != xsize || bgYsize != ysize) {
  963.         if (bgImage != NULL) free(bgImage);
  964.         bgImage = (long *) malloc(xsize * ysize * sizeof(long));
  965.         bgXsize = xsize; bgYsize = ysize;
  966.     }
  967.  
  968.     for(y=0; y<ysize; y++) {
  969.         getrow(image,buf,y,0);    /* Red */
  970.         for (x=0; x<xsize; x++) bgImage[y*xsize + x]  = buf[x] | 0xff000000;
  971.         getrow(image,buf,y,1);    /* Green */
  972.         for (x=0; x<xsize; x++) bgImage[y*xsize + x] |= buf[x] << 8;
  973.         getrow(image,buf,y,2);    /* Blue */
  974.         for (x=0; x<xsize; x++) bgImage[y*xsize + x] |= buf[x] << 16;
  975.     }
  976.     return TRUE;
  977. }
  978.  
  979. /******************************************************************************
  980.  
  981.     Menus
  982.  
  983. ******************************************************************************/
  984. MakeMenu() {
  985.     freepup(mainMenu);
  986.     mainMenu = defpup("Morph Edit %t");
  987.     addtopup(mainMenu, "Performance%x14%l");
  988.     addtopup(mainMenu, clickMode==selmoveVertices ?
  989.             "> Select/Move%x1" : "   Select/Move%x1");
  990.     addtopup(mainMenu, clickMode==addVertices ?
  991.             "> Add Vertices%x2" :         "   Add Vertices%x2");
  992.     addtopup(mainMenu, clickMode==connectVertices ?
  993.             "> Add Connections%x3" :     "   Add Connections%x3");
  994.     addtopup(mainMenu, "   Draw Triangles%x10%l");
  995.     addtopup(mainMenu, "Vertex Color %m", vColorMenu);
  996.     addtopup(mainMenu, "Connection Color %m %l", cColorMenu);
  997.     addtopup(mainMenu, "Read file blah.rgb%x6");
  998.     addtopup(mainMenu, "Read file blah.cnx%x8");
  999.     addtopup(mainMenu, "Save as blah.cnx%x7%l");
  1000.     addtopup(mainMenu, "Add to Target List%x12");
  1001.     addtopup(mainMenu, "Go to Target %m", targetGotoMenu);
  1002.     addtopup(mainMenu, "Delete Target from List %m%l", targetDeleteMenu);
  1003.     addtopup(mainMenu, "Exit%x99");
  1004. }
  1005.  
  1006. int
  1007. DoMenu() {
  1008.     int item, myDoneFlag;
  1009.  
  1010.     myDoneFlag = FALSE;
  1011.     switch (item = dopup(mainMenu)) {
  1012.     case 1: /* Select/Move Vertices */
  1013.         clickMode = selmoveVertices;
  1014.         SelectVertex(-1);
  1015.         DrawWindow();
  1016.         MakeMenu();
  1017.         break;
  1018.     case 2: /* Add Vertices */
  1019.         clickMode = addVertices;
  1020.         SelectVertex(-1);
  1021.         DrawWindow();
  1022.         MakeMenu();
  1023.         break;
  1024.     case 3: /* Connect Vertices */
  1025.         clickMode = connectVertices;
  1026.         SelectVertex(-1);
  1027.         DrawWindow();
  1028.         MakeMenu();
  1029.         break;
  1030.     /* 4: Vertex Color */
  1031.     /* 5: Connection Color */
  1032.     case 6: /* Read Background image */
  1033.         ReadImg("blah.rgb");
  1034.         DrawWindow();
  1035.         break;
  1036.     case 7: /* Save connection file */
  1037.         WriteCnx("blah.cnx");
  1038.         break;
  1039.     case 8: /* Read connection file */
  1040.         ReadCnx("blah.cnx");
  1041.         DrawWindow();
  1042.         break;
  1043.     case 10: /* Draw Triangles */
  1044.         CnxToTri();
  1045.         DrawWindow();
  1046.         nTriangles = 0;
  1047.         break;
  1048.     /* 11: Goto Target */
  1049.     case 12: /* Add target to list */
  1050.         AddTarget();
  1051.         MakeTargetMenus();
  1052.         MakeMenu();
  1053.         break;
  1054.     /* 13: Delete target from list */
  1055.     case 14: /* Performance */
  1056.         performFlag = TRUE;
  1057.     autoRun = FALSE;
  1058.         thisTarget = destTarget = -1;
  1059.         SetPerformGfx();
  1060.         DrawPerformWindow();
  1061.         break;
  1062.     case 99: /* Exit */
  1063.     myDoneFlag = TRUE;
  1064.     break;
  1065.     default:
  1066.         /* Sub-menus... */
  1067.         if (item < 20) break;
  1068.         else if (item < 30)
  1069.             /* Set Connection Color (color 0 is menu #21) */
  1070.             cColor = colorList[item - 21];
  1071.         else if (item < 40)
  1072.             /* Set Vertex Color (color 0 is menu #31) */
  1073.             vColor = colorList[item - 31];
  1074.         else if (item < 60) {
  1075.             /* Go to a target in the list (target[0] is menu #40) */
  1076.         UseTarget(item - 40);
  1077.         SelectVertex(-1);
  1078.         DrawWindow();
  1079.         }
  1080.         else {
  1081.             /* Delete a target from list (target[0] is menu #60) */
  1082.         DeleteTarget(item - 60);
  1083.         MakeTargetMenus();
  1084.         MakeMenu();
  1085.         }
  1086.         break;
  1087.     }
  1088.  
  1089.     return myDoneFlag;
  1090. }
  1091.  
  1092. DrawWindow() {
  1093.     int i, v0, v1;
  1094.     long currentColor;
  1095.  
  1096.     /* Clear the screen */
  1097.     if (bgImage == NULL) {
  1098.         cpack(RGB_GRAY);
  1099.         clear();
  1100.     } else {
  1101.         rectzoom(2.0, 2.0);
  1102.         lrectwrite(0, 0, 255, 255, bgImage);
  1103.     }
  1104.  
  1105.     /* Draw the triangles */
  1106.     currentColor = 0;
  1107.     for (i=0; i<nTriangles; i++) {
  1108.         currentColor++;
  1109.         currentColor = currentColor % (sizeof(triColorList)/sizeof(long));
  1110.         cpack(triColorList[currentColor]);
  1111.         bgnpolygon();
  1112.         v2f(&vertexList[triangleList[i].v0].x);
  1113.         v2f(&vertexList[triangleList[i].v1].x);
  1114.         v2f(&vertexList[triangleList[i].v2].x);
  1115.         endpolygon();
  1116.     }
  1117.  
  1118.     /* Draw the Connections */
  1119.     for (i=0; i<nCnx; i++) {
  1120.         cpack(cnxList[i].color + (cnxList[i].selected ? RGB_BRIGHTER : 0));
  1121.         v0 = cnxList[i].v0;
  1122.         v1 = cnxList[i].v1;
  1123.         move2(vertexList[v0].x, vertexList[v0].y);
  1124.         draw2(vertexList[v1].x, vertexList[v1].y);
  1125.     }
  1126.  
  1127.     /* Draw the Vertices */
  1128.     for (i=0; i<nVertices; i++) {
  1129.         cpack(vertexList[i].color + (vertexList[i].selected?RGB_BRIGHTER:0));
  1130.         move2(vertexList[i].x, vertexList[i].y);
  1131.         rmv2(-crossArm, 0.0);
  1132.         rdr2(crossArm + crossArm, 0.0);
  1133.         rmv2(-crossArm, -crossArm);
  1134.         rdr2(0.0, crossArm + crossArm);
  1135.     }
  1136.  
  1137.     swapbuffers();
  1138. }
  1139.  
  1140. /*************************************************************************
  1141.  
  1142.     Connect to triangle rep routines
  1143.  
  1144. *************************************************************************/
  1145.  
  1146. void
  1147. XRefEdge(int iVertex, int iCnx);
  1148. int
  1149. NextEdge(int iVertex, int iEdge);
  1150. int
  1151. OtherEnd(int iEdge, int iVertex);
  1152.  
  1153. int
  1154. CompareTheta(float *th0, float *th1) {
  1155.     return (*th0 > *th1) ? -1 : 1;
  1156. }
  1157.  
  1158. void
  1159. CnxToTri() {
  1160.     /* My own vertex-edge list for sorting */
  1161.     struct mel_tag {
  1162.         float theta;
  1163.         int edge;
  1164.     } myEdgeList[MAXEDGESPERVERTEX];
  1165.  
  1166.     int i, j, k, myNEdges, myObtuse;
  1167.     int v0, v1, v2, v3, e0, e1, e2;
  1168.     float dTheta;
  1169.  
  1170.     /* Find all the edges connected to each vertex */
  1171.     for (i=0; i<nVertices; i++) vertexEdges[i].nEdges = 0;
  1172.     for (i=0; i<nCnx; i++) {
  1173.         XRefEdge(cnxList[i].v0, i);
  1174.         XRefEdge(cnxList[i].v1, i);
  1175.     }
  1176.  
  1177.     /* Measure and order edges at each vertex. */
  1178.     for (i=0; i<nVertices; i++) {
  1179.         /* Collect the edges, and sort them into clockwise order */
  1180.         if ((myNEdges = vertexEdges[i].nEdges) <= 0) continue;
  1181.         for (j=0; j<myNEdges; j++) {
  1182.             myEdgeList[j].edge = vertexEdges[i].edge[j].index;
  1183.             v0 = cnxList[myEdgeList[j].edge].v0;
  1184.             v1 = cnxList[myEdgeList[j].edge].v1;
  1185.             myEdgeList[j].theta = fatan2(
  1186.                     vertexList[v0].y - vertexList[v1].y,
  1187.                     vertexList[v0].x - vertexList[v1].x);
  1188.             if (v0 != i)
  1189.                 if (myEdgeList[j].theta < 0.0)
  1190.                     myEdgeList[j].theta += M_PI;
  1191.                 else
  1192.                     myEdgeList[j].theta -= M_PI;
  1193.         }
  1194.         qsort((char *) myEdgeList, myNEdges, sizeof(struct mel_tag),
  1195.                 CompareTheta);
  1196.  
  1197.         /* Copy edges back into vertexEdge in clockwise order.
  1198.            Mark obtuse wedges radiating from vertex */
  1199.         for (j=0; j<myNEdges-1; j++) {
  1200.             dTheta = myEdgeList[j].theta - myEdgeList[j+1].theta;
  1201.             if (dTheta < 0.0) dTheta += M_PI + M_PI;
  1202.             vertexEdges[i].edge[j].marked = dTheta > M_PI;
  1203.             vertexEdges[i].edge[j].index = myEdgeList[j].edge;
  1204.         }
  1205.         dTheta = (myEdgeList[myNEdges-1].theta - myEdgeList[0].theta);
  1206.         if (dTheta < 0.0) dTheta += M_PI + M_PI;
  1207.         vertexEdges[i].edge[myNEdges-1].marked = dTheta > M_PI;
  1208.         vertexEdges[i].edge[myNEdges-1].index = myEdgeList[myNEdges-1].edge;
  1209.     }
  1210.  
  1211.     /* For each vertex, try to make triangles out of every edge */
  1212.     nTriangles = 0;
  1213.     for (i=0; i<nVertices; i++) {
  1214.         v0 = i;
  1215.         for (j=0; j<vertexEdges[i].nEdges; j++) {
  1216.             if ((e0 = NextEdge(v0, vertexEdges[i].edge[j].index)) < 0) continue;
  1217.             v1 = OtherEnd(e0, v0);
  1218.             if ((e1 = NextEdge(v1, e0)) < 0) continue;
  1219.             v2 = OtherEnd(e1, v1);
  1220.             if ((e2 = NextEdge(v2, e1)) < 0) continue;
  1221.             v3 = OtherEnd(e2, v2);
  1222.             if (v3 == v0) AddTriangle(v0, v1, v2);
  1223.         }
  1224.     }
  1225. }
  1226.  
  1227. void
  1228. XRefEdge(int iVertex, int iCnx) {
  1229.     /* Add this vertex-edge pair to the per-vertex list */
  1230.     int n;
  1231.     n = vertexEdges[iVertex].nEdges;
  1232.     vertexEdges[iVertex].edge[n].index = iCnx;
  1233.     vertexEdges[iVertex].nEdges++;
  1234. }
  1235.  
  1236. int
  1237. NextEdge(int iVertex, int iEdge) {
  1238.     /* Get the edge out if vertex iVertex which follows edge iEdge in
  1239.        clockwise order.
  1240.        Return false if that wedge is already marked.  Otherwise, mark it. */
  1241.     int i;
  1242.  
  1243.     for (i=0; i<vertexEdges[iVertex].nEdges; i++) {
  1244.         if (vertexEdges[iVertex].edge[i].index == iEdge) {
  1245.             /* Found it. Marked already? */
  1246.             if (vertexEdges[iVertex].edge[i].marked)
  1247.                 return -1;
  1248.             else {
  1249.                 /* Not marked.
  1250.                    Mark it, then return next one, or 0th one if we're at end */
  1251.                 vertexEdges[iVertex].edge[i].marked = TRUE;
  1252.                 if (i<vertexEdges[iVertex].nEdges-1)
  1253.                     return vertexEdges[iVertex].edge[i+1].index;
  1254.                 else
  1255.                     return vertexEdges[iVertex].edge[0].index;
  1256.             }
  1257.         }
  1258.     }
  1259.  
  1260.     fprintf(stderr,
  1261.             "Data problems in NextEdge, vertex %d, edge %d\n", iVertex, iEdge);
  1262.     return -1;
  1263. }
  1264.  
  1265. int
  1266. OtherEnd(int iEdge, int iVertex) {
  1267.     /* Find the vertex at the other end of edge iEdge from iVertex */
  1268.     if (cnxList[iEdge].v0 == iVertex) return cnxList[iEdge].v1;
  1269.     else return cnxList[iEdge].v0;
  1270. }
  1271.  
  1272. /*****************************************************************************
  1273.  
  1274.     Target management
  1275.  
  1276. *****************************************************************************/
  1277. AddTarget() {
  1278.     int i, j;
  1279.  
  1280.     if (nTargets >= MAXTARGETS) return;
  1281.  
  1282.     /* Make a copy of the Texture Image */
  1283.     target[nTargets].image = (long *) malloc(sizeof(long) * bgXsize * bgYsize);
  1284.     target[nTargets].xSize = bgXsize;
  1285.     target[nTargets].ySize = bgYsize;
  1286.     for (i=0; i<bgXsize*bgYsize; i++)
  1287.         target[nTargets].image[i] = bgImage[i];
  1288.  
  1289.     /* Make a copy of the vertex list */
  1290.     target[nTargets].vertexList =
  1291.         (struct vertlist_tag *) malloc(sizeof(struct vertlist_tag) * nVertices);
  1292.     target[nTargets].nVertices = nVertices;
  1293.     for (i=0; i<nVertices; i++)
  1294.         target[nTargets].vertexList[i] = vertexList[i];
  1295.  
  1296.     /* Make a copy of the connection list (just to keep around ) */
  1297.     target[nTargets].cnxList =
  1298.         (struct cnxlist_tag *) malloc(sizeof(struct cnxlist_tag) * nCnx);
  1299.     target[nTargets].nCnx = nCnx;
  1300.     for (i=0; i<nCnx; i++)
  1301.         target[nTargets].cnxList[i] = cnxList[i];
  1302.     
  1303.     /* Get a current triangulization and copy it too */
  1304.     CnxToTri();
  1305.     target[nTargets].triangleList =
  1306.         (struct tri_tag *) malloc(sizeof(struct tri_tag) * nTriangles);
  1307.     target[nTargets].nTriangles = nTriangles;
  1308.     for (i=0; i<nTriangles; i++)
  1309.         target[nTargets].triangleList[i] = triangleList[i];
  1310.     nTriangles = 0;
  1311.  
  1312.     /* Assign a texture id */
  1313.     for (i=1; i<=MAXTARGETS; i++) {
  1314.         for (j=0; j<nTargets; j++)
  1315.             if (target[j].textureIndex == i) break;
  1316.  
  1317.         if (j >= nTargets) {
  1318.             /* i is an unused index. Assign it. */
  1319.             target[nTargets].textureIndex = i;
  1320.             break;
  1321.         }
  1322.     }
  1323.  
  1324.     nTargets++;
  1325. }
  1326.  
  1327. UseTarget(int iTarget) {
  1328.     /* Make one of the existing targets the current working image/cnx combo */
  1329.     int i;
  1330.  
  1331.     /* Reallocate image array if the dimensions are different */
  1332.     if (target[iTarget].xSize != bgXsize || target[iTarget].ySize != bgYsize) {
  1333.     free(bgImage);
  1334.     bgXsize = target[iTarget].xSize;
  1335.     bgYsize = target[iTarget].ySize;
  1336.     bgImage = (long *) malloc(sizeof(long) * bgXsize * bgYsize);
  1337.     }
  1338.     for (i=0; i<bgXsize*bgYsize; i++)
  1339.     bgImage[i] = target[iTarget].image[i];
  1340.  
  1341.     /* Copy the vertex list back */
  1342.     nVertices = target[iTarget].nVertices;
  1343.     for (i=0; i<nVertices; i++) vertexList[i] = target[iTarget].vertexList[i];
  1344.  
  1345.     /* Copy the connection list back */
  1346.     nCnx = target[iTarget].nCnx;
  1347.     for (i=0; i<nCnx; i++) cnxList[i] = target[iTarget].cnxList[i];
  1348. }
  1349.  
  1350. DeleteTarget(int iTarget) {
  1351.     /* Free the memory for the indicated target, and collapse the list */
  1352.     int i;
  1353.  
  1354.     free(target[iTarget].image);
  1355.     free(target[iTarget].vertexList);
  1356.     free(target[iTarget].cnxList);
  1357.     free(target[iTarget].triangleList);
  1358.  
  1359.     for (i=iTarget; i<nTargets-1; i++) target[i] = target[i+1];
  1360.     nTargets--;
  1361. }
  1362.  
  1363. MakeTargetMenus() {
  1364.     int i;
  1365.     char buf[30];
  1366.  
  1367.     freepup(targetGotoMenu);
  1368.     targetGotoMenu = defpup("Go to Target:%t");
  1369.     for (i=0; i<nTargets; i++) {
  1370.         sprintf(buf, "Target %d %%x%d", i+1, 40+i);
  1371.         addtopup(targetGotoMenu, buf, 0);
  1372.     }
  1373.     freepup(targetDeleteMenu);
  1374.     targetDeleteMenu = defpup("Delete Target:%t");
  1375.     for (i=0; i<nTargets; i++) {
  1376.         sprintf(buf, "Target %d %%x%d", i+1, 60+i);
  1377.         addtopup(targetDeleteMenu, buf, 0);
  1378.     }
  1379. }
  1380.  
  1381. AnimateTransition() {
  1382.     int i, iVertex, iFrame, nFrames;
  1383.     float p, f, omf;
  1384.  
  1385. /* Bob Drebin's workaround hack for 3.3.2 texture management bug */
  1386. /* This code causes flashes on my PI, even resetting RGBmode & doublebuffer
  1387.     tevbind(TV_ENV0, 0);
  1388.     acsize(16);
  1389.     gconfig();
  1390.     acsize(0);
  1391.     gconfig();
  1392.     tevbind(TV_ENV0, 1);
  1393. */
  1394.  
  1395.     /* Set up our vertices once if no morphing happens */
  1396.     if (thisTarget<0) {
  1397.         if (destTarget<0) return;
  1398.         nTmpVertices = target[destTarget].nVertices;
  1399.         for (iVertex=0; iVertex<nTmpVertices; iVertex++) {
  1400.             tmpVertexList[iVertex].x =
  1401.                 target[destTarget].vertexList[iVertex].x;
  1402.             tmpVertexList[iVertex].y =
  1403.                 target[destTarget].vertexList[iVertex].y;
  1404.         }
  1405.     }
  1406.  
  1407.  
  1408.     /* Loop through the frames */
  1409.     nFrames = frameCount[currentSpeed];
  1410.     if ((thisTarget<0 || destTarget<0) && showTwins) nFrames = 1;
  1411.     for (iFrame=1; !flushQueue && iFrame<=nFrames; iFrame++) {
  1412.         p = iFrame / (float) nFrames;
  1413.         f = (-p-p + 3.0)*p*p;
  1414.         if (flushQueue = getbutton(LEFTCTRLKEY)) f = 1.0;
  1415.         omf = 1.0 - f;
  1416.  
  1417.     /* Do a cross-dissolve with alpha values */
  1418.     thisTargetColor = destTargetColor = RGB_WHITE;
  1419.     if (!showTwins) {
  1420.         thisTargetColor |= ((int)(255*omf)) <<24;
  1421.         destTargetColor |= ((int)(255*  f)) <<24;
  1422.     } else {
  1423.         thisTargetColor |= 255 << 24;
  1424.         destTargetColor |= 255 << 24;
  1425.     }
  1426.  
  1427.  
  1428.         /* Move the vertices */
  1429.         if (thisTarget>=0 && destTarget>=0) {
  1430.             for (iVertex=0; iVertex<nTmpVertices; iVertex++) {
  1431.                 tmpVertexList[iVertex].x =
  1432.                     (1.0-f) * target[thisTarget].vertexList[iVertex].x +
  1433.                     (    f) * target[destTarget].vertexList[iVertex].x;
  1434.                 tmpVertexList[iVertex].y =
  1435.                     (1.0-f) * target[thisTarget].vertexList[iVertex].y +
  1436.                     (    f) * target[destTarget].vertexList[iVertex].y;
  1437.             }
  1438.         }
  1439.  
  1440.         DrawPerformWindow();
  1441.     }
  1442.  
  1443. }
  1444.  
  1445. DrawPerformWindow() {
  1446.     struct vertlist_tag *vl, *tvl;
  1447.     struct tri_tag *tl;
  1448.     int nv, nt, iTri;
  1449.  
  1450.     /* Clear the screen */
  1451.     reshapeviewport();
  1452.     cpack(RGB_BLACK);
  1453.     clear();
  1454.  
  1455.     if (performAspect > 1.0)
  1456.     /* Higher than wide, fit image side-to-side */
  1457.     ortho2(0.0, 1.0,
  1458.         0.0 - (performAspect-1.0)/2.0, 1.0 + (performAspect-1.0)/2.0);
  1459.     else
  1460.     /* Wider than high, fit top-to-bottom */
  1461.     ortho2(0.0 - (1.0/performAspect-1.0)/2.0,
  1462.            1.0 + (1.0/performAspect-1.0)/2.0,
  1463.            0.0, 1.0);
  1464.  
  1465.     /* Draw this target image */
  1466.     if (thisTarget>=0) {
  1467.     /* If showTwins is set, show this image in the left half of window */
  1468.     if (showTwins) viewport(0, performXSize/2, 0, performYSize);
  1469.  
  1470.         texbind(TX_TEXTURE_0, target[thisTarget].textureIndex);
  1471.         cpack(thisTargetColor);
  1472.         vl = tmpVertexList;
  1473.         nv = nTmpVertices;
  1474.         tvl = target[thisTarget].vertexList;
  1475.         tl = target[thisTarget].triangleList;
  1476.         nt = target[thisTarget].nTriangles;
  1477.         for (iTri=0; iTri<nt; iTri++) {
  1478.             bgnpolygon();
  1479.             t2f(&tvl[tl[iTri].v0].x);
  1480.             v2f( &vl[tl[iTri].v0].x);
  1481.             t2f(&tvl[tl[iTri].v1].x);
  1482.             v2f( &vl[tl[iTri].v1].x);
  1483.             t2f(&tvl[tl[iTri].v2].x);
  1484.             v2f( &vl[tl[iTri].v2].x);
  1485.             endpolygon();
  1486.         }
  1487.  
  1488.     if (showMesh && (showTwins || destTarget<0)) DrawMesh(thisTarget, vl);
  1489.     }
  1490.  
  1491.     /* Draw destination target image */
  1492.     if (destTarget>=0) {
  1493.     /* If showTwins is set, show this image in the right half of window */
  1494.     if (showTwins)
  1495.         viewport(performXSize/2+1, performXSize, 0, performYSize);
  1496.  
  1497.         texbind(TX_TEXTURE_0, target[destTarget].textureIndex);
  1498.         cpack(destTargetColor);
  1499.         vl = tmpVertexList;
  1500.         nv = nTmpVertices;
  1501.         tvl = target[destTarget].vertexList;
  1502.         tl = target[destTarget].triangleList;
  1503.         nt = target[destTarget].nTriangles;
  1504.         for (iTri=0; iTri<nt; iTri++) {
  1505.             bgnpolygon();
  1506.             t2f(&tvl[tl[iTri].v0].x);
  1507.             v2f( &vl[tl[iTri].v0].x);
  1508.             t2f(&tvl[tl[iTri].v1].x);
  1509.             v2f( &vl[tl[iTri].v1].x);
  1510.             t2f(&tvl[tl[iTri].v2].x);
  1511.             v2f( &vl[tl[iTri].v2].x);
  1512.             endpolygon();
  1513.         }
  1514.  
  1515.     if (showMesh) DrawMesh(destTarget, vl);
  1516.     }
  1517.  
  1518.     swapbuffers();
  1519. }
  1520.  
  1521. DrawMesh(int iTarget, struct vertlist_tag *vl) {
  1522.     int i, v0, v1;
  1523.     struct target_tag *t;
  1524.  
  1525.     t = &target[iTarget];
  1526.     texbind(TX_TEXTURE_0, 0);
  1527.  
  1528.     /* Draw the Connections */
  1529.     for (i=0; i<t->nCnx; i++) {
  1530.         cpack(t->cnxList[i].color | 255<<24);
  1531.         v0 = t->cnxList[i].v0;
  1532.         v1 = t->cnxList[i].v1;
  1533.         move2(vl[v0].x, vl[v0].y);
  1534.         draw2(vl[v1].x, vl[v1].y);
  1535.     }
  1536.  
  1537.     /* Draw the Vertices */
  1538.     for (i=0; i<t->nVertices; i++) {
  1539.         cpack(t->vertexList[i].color | 255<<24);
  1540.         move2(vl[i].x, vl[i].y);
  1541.         rmv2(-crossArm, 0.0);
  1542.         rdr2(crossArm + crossArm, 0.0);
  1543.         rmv2(-crossArm, -crossArm);
  1544.         rdr2(0.0, crossArm + crossArm);
  1545.     }
  1546. }
  1547.  
  1548.